package encheres.manager.impl;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.hibernate.HibernateException;
import org.omg.CORBA.ORB;

import encheres.dao.ICategorieDAO;
import encheres.dao.IClientDAO;
import encheres.dao.IProduitDAO;
import encheres.dao.entities.Categorie;
import encheres.dao.entities.Client;
import encheres.dao.entities.Produit;
import encheres.dao.entities.Vente;
import encheres.dao.impl.CategorieDAOImpl;
import encheres.dao.impl.ClientDAOImpl;
import encheres.dao.impl.ProduitDAOImpl;
import encheres.manager.SessionManager;
import encheres.manager.corba.C_Enchere;
import encheres.manager.corba.C_Produit;
import encheres.manager.corba.C_Filtre;
import encheres.manager.corba.I_ProduitPOA;

/**
 * Implémente le skeleton de Produit.
 * @author Nicolas
 *
 */
public class I_ProduitImpl extends I_ProduitPOA {
	
	/** bus par lequel les requêtes sur les objets transitent. */
	private ORB orb;
	/** service DAO pour gérer les objets Produit avec la BD. */
	private IProduitDAO produitDao = new ProduitDAOImpl();
	/** service DAO pour gérer les objets Categorie avec la BD. */
	private ICategorieDAO categorieDao = new CategorieDAOImpl();
	/** service DAO pour gérer les objets Client avec la BD. */
	private IClientDAO clientDao = new ClientDAOImpl();

	/**
	 * Liste les produits d'une catégorie
	 * 
	 * @param idCategorie l'identifiant en base de données de la catégorie
	 * @return la liste des produits de la catégorie triés par date de mise aux enchères
	 */
	public C_Produit[] listerProduitsParCategorie(int idCategorie) {
		C_Produit[] tabProduits = null;
		List<Produit> listProduits = new ArrayList<Produit>();
		List<Produit> listProduitsTries = new ArrayList<Produit>();
//		DateFormat format = new SimpleDateFormat("dd/MM/yyyy");
		listProduits = this.produitDao.listProduits();
		
		// filtrer les produits en ne concervant que ceux de la catégorie
		for(Produit produit : listProduits) {
			if(produit.getCategorie().getIdCategorie()==idCategorie){
				listProduitsTries.add(produit);
			}
		}
		
		// convertir la liste triée en tableau de C_Produit
		int taille = listProduitsTries.size();
		tabProduits = new C_Produit[taille];
		// liste tous les produits
		for(int i=0; i<taille; i++){
			Produit produit = listProduitsTries.get(i);
//			int idCategorieCourante = -1;
//			if(produit.getCategorie() != null){
//				idCategorieCourante = produit.getCategorie().getIdCategorie();
//			}
			tabProduits[i] = new C_Produit(produit.getIdProduit(),
					produit.getLibelleProduit(),
					produit.getDescriptifProduit(),
					produit.getCategorie().getIdCategorie(),
					produit.getCategorie().getNomCategorie(),
					produit.getClient().getIdClient(),
					produit.getClient().getLoginClient(),
					produit.getPrixDepartProduit(),
					produit.getPrixAcceptationProduit(),
					produit.getDateEcheanceProduit().toString(),
					this.getTabEncheres(produit.getVentes()));
		}
		
		return tabProduits;
	}

	/**
	 * Liste les produits à l'aide d'un filtre
	 * 
	 * @param filtre le filtre à appliquer
	 * @return la liste filtrée des produits triés par date de mise aux enchères
	 */
	public C_Produit[] listerProduitsAvecFiltre(final C_Filtre filtre, final int idCategorie) {
		C_Produit[] tabProduits = null;
		
		if(filtre == C_Filtre.Tous){
			List<Produit> listProduits = this.produitDao.listProduits();
			int taille = listProduits.size();
			tabProduits = new C_Produit[taille];
			// liste tous les produits
			for(int i=0; i<taille; i++){
				Produit produit = listProduits.get(i);
				tabProduits[i] = new C_Produit(produit.getIdProduit(),
						produit.getLibelleProduit(),
						produit.getDescriptifProduit(),
						produit.getCategorie().getIdCategorie(),
						produit.getCategorie().getNomCategorie(),
						produit.getClient().getIdClient(),
						produit.getClient().getLoginClient(),
						produit.getPrixDepartProduit(),
						produit.getPrixAcceptationProduit(),
						produit.getDateEcheanceProduit().toString(),
						this.getTabEncheres(produit.getVentes()));
			}
		} else if(filtre == C_Filtre.ParCategorie){
			// filtrer la liste des produits en gardant juste ceux concernés par la catégorie
			tabProduits = this.listerProduitsParCategorie(idCategorie);
		}
		return tabProduits;

	}
	
	/**
	 * Transforme une liste de Vente en un tableau de C_Enchere
	 * @param listEncheres la listedes objets Vente
	 * @return le tableau d'objet C_Enchere
	 */
	private C_Enchere[] getTabEncheres(final Set<Vente> ensembleEncheres){
		C_Enchere[] tabEncheres;
		DateFormat format = new SimpleDateFormat("dd/MM/yyyy");
		if(ensembleEncheres != null) {
			List<Vente> listEncheres = new ArrayList<Vente>(ensembleEncheres);
			int taille = listEncheres.size();
			tabEncheres = new C_Enchere[taille];
			for(int i=0; i<taille; i++) {
				Vente v = listEncheres.get(i);
				tabEncheres[i] = new C_Enchere(v.getProduit().getIdProduit(), v.getClient().getIdClient(),v.getClient().getLoginClient(), v.getPrixVente(), format.format(v.getId().getDateVente()));
			}
		} else {
			tabEncheres = new C_Enchere[0];
		}
		return tabEncheres;
	}

	/**
	 * Place une enchère sur un produit, pour l'utilisateur de la session courante
	 * 
	 * @param idProduit l'identifiant du produit
	 * @param montant le montant de l'enchère
	 * @return 1 en cas de succès, 0 en cas d'échec de la transaction (enchère d'un montant supérieur déjà enregistrée) et -1 en cas d'erreur de session (utilisateur non identifié)
	 */
	synchronized public int encherir(int idProduit, float montant, int idSession) {
		try {
			Integer idClient = SessionManager.findClientId(idSession);
			if (idClient == null) {
				return -1;
			}
			Client client = clientDao.findClient(idClient);
			Produit produit = produitDao.findProduit(idProduit);
			//On vérifie que le montant est valide
			if (montant < produit.getPrixDepartProduit() || montant > produit.getPrixAcceptationProduit()) {
				return -2;
			}
			//On vérifie qu'il n'y a aucune vente d'un montant supérieur déja existante
			Iterator<Vente> it = produit.getVentes().iterator();
			while (it.hasNext()) {
				Vente vente = it.next();
				if (vente.getPrixVente() >= montant) {
					return 0;
				}
			}
			produitDao.encherirProduit(client, produit, montant, new Date());
			return 1;
		} catch (HibernateException e) {
			e.printStackTrace();
			return -1;
		}
	}

	/**
	 * Créé un produit proposé par un utilisateur.
	 * 
	 * @return 1 en cas de succès, 0 en cas d'échec de l'ajout (HibernateException ou n'arrive pas à convertir la date d'échéance) et -1 en cas d'erreur de session (utilisateur non identifié)
	 * @throws ParseException 
	 */
	public int creerProduit(String nom, int idCategorie, String description, String dateEcheance, float prixDepart,	float prixAcceptation,int idSession) {
		try {
			//Vérifier que les paramètres en entrée sont corrects
			DateFormat format = new SimpleDateFormat("dd/MM/yyyy");
			Date date = format.parse(dateEcheance);
			if (date.before(new Date())) return 0;
			if (prixDepart <= 0) return 0;
			if (prixDepart >= prixAcceptation) return 0;

			// trouver la catégorie
			Categorie categorie = this.categorieDao.findCategorie(idCategorie);
			// trouver le client
			Integer idClient = SessionManager.findClientId(idSession);
			if (idClient == null) return -1;
			
			Client vendeur = clientDao.findClient(idClient);
			Produit produit = new Produit(vendeur, categorie, nom, description, prixDepart,prixAcceptation,format.parse(dateEcheance),null);
			this.produitDao.proposerProduit(produit);
			return 1;
		} catch (HibernateException e) {
			e.printStackTrace();
			return 0;
		} catch (ParseException e) {
			e.printStackTrace();
			return 0;
		} 
	}
	
	public C_Produit detailsProduit(int idProduit) {
		try {
			Produit produit = produitDao.findProduit(idProduit);
			C_Produit res = new C_Produit(produit.getIdProduit(),
					produit.getLibelleProduit(),
					produit.getDescriptifProduit(),
					produit.getCategorie().getIdCategorie(),
					produit.getCategorie().getNomCategorie(),
					produit.getClient().getIdClient(),
					produit.getClient().getLoginClient(),
					produit.getPrixDepartProduit(),
					produit.getPrixAcceptationProduit(),
					produit.getDateEcheanceProduit().toString(),
					this.getTabEncheres(produit.getVentes()));
			return res;
		} catch (HibernateException e) {
			e.printStackTrace();
			return null;
		}
	}
	
	/**
	 * Ferme le bus par lequel les requêtes sur les objets transitent.
	 */
	public void shutdown() {
		orb.shutdown(false);
	}
	
	/**
	 * setteur sur le bus par lequel les requêtes sur les objets transitent.
	 * @param orb_val le nouveau bus par lequel les requêtes sur les objets transitent.
	 */
	public void setORB(ORB orb_val) {
		orb = orb_val;
	}
}
